package kontlin.zoufeng.com.kotlin

import android.os.Bundle
import android.support.v7.app.AppCompatActivity
import android.util.Log
import android.view.View
import java.io.File
import java.util.*
import kotlin.collections.ArrayList

class BaseGrammar : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        test1()
        test2()
        fcn1()
        fcn2(3)
        test11()

        test12()
    }

    /**
     * 常量 变量
     */
    fun test1() {
        val a = "ee"  //常量 必须赋值 且 值不可再改变

        var b = 1  //变量 必须赋值 值可变
//        Log.e("kotlin",""+b)
    }


    /**
     * 基本语法
     */
    fun test2() {
        // 1.数据类型
        // 规则与java基本相同
        // 格式:  var 变量名： 类型 = 值   注意：类型首字母大写
        var a: Int = 3  //可省略类型 var a = 3
        Log.e("kotlin", "" + a)


        //2.文本模版
        Log.e("kotlin", "" + "每天跑" + a + "步")
        Log.e("kotlin", "" + "每天跑${a}步")


        //3.元组Tuple
        //kotlin分为二元组Pair和三元组Triple，最高三元组
        var b = Triple(1, "www", "三元组")
        var c = Pair(1, "二元组")
        Log.e("kotlin", "${b.first}--${b.second}--${b.third} ===${c.first} ===${c.second}")


        //4.可空类型 nullable
        var d: String?  // 设置空
        d = ""//使用的时候不可得为空 也就避免了空指针问题
        Log.e("kotlin", "每天跑${d}步")


        //5.创建对象
        //与java不同 移除了new关键字
        var date = Date()


        //6.引用相等和结构相等
        //=== !== 比较引用地址            类似java中的==
        //== !=  equals() 比较结构(内容)  类似java中equals
        var e = File("/user/bin")
        var f = File("/user/bin")
        Log.e("kotlin", "比较是否相同${e.equals(f)}")


        //7.区间Range
        var aa = 1..100 //整数有能力循环
//        for (a in aa){
//            Log.e("kotlin", "每天跑${a}步")
//        }
//
        var ab = "a".."z"
        Log.e("kotlin", "是否包含${"d" in ab}")

        var ac = (1..100).step(5) //步进
        for (a in ac) {
            Log.e("kotlin", "每天跑${a}步")
        }

    }

    /**
     *流程语句
     */
    fun test3() {
        //流程语句与java相比较
//        a.流程语句可做表达 返回结果
//        b.when语句也就是java中的swich语句 做了较大的增强

        var aa = 1..100 //整数有能力循环

        //1.if语句 与java相同
        if (true) true else false  //简写

        //2.when  增强
//        a.参数和比较条件都可以为表达式
        when (Math.abs(-3)) {
            3 -> true
            Math.abs(-3) -> true
            in 1..3 -> true
            is Int -> true
            else -> false
        }

//        b.无参 相当于多if
        when {
            3 > 4 -> true
            3 < 4 -> true
            else -> false
        }

//     3.while 与java类似

//     4.for
        for (a in aa) {
        }

        val arr = arrayOf("aa", "bb", "cc")
        for (i in arr.indices) {
            Log.e("aa", "" + arr[i])
        }
    }


    /**
     *字符串
     *
     * 与java基本相同
     *
     * 字符两个常用方法
     * isDigit（） 判断是否数字
     * isLetter（） 判断是否字母
     */


    /**
     *函数
     */
    //1.Unit类似java中的void  但是可省略
    fun test4(x: Any): Unit {

    }

    //  2.可变参数
    fun test5(vararg x: Int) {
        for (i in x) {
            Log.e("kotlin", "可变参数${i}")
        }
    }

    //3.简化函数
    fun test6(x: Int) = Log.e("kotlin", "简化函数${x}")

    //4.本地函数（函数内部函数）
    fun test7(x: Int) {
        fun test77() {  //作用范围该函数类
        }
    }

    //4顶级函数
    //不属于任何类 对象 接口，直接定义源码文件中 供所有类可调用

    //5.参数命名  可用指定键值方式 这样就可以不按顺序传参了
    fun test8() {
        test7(x = 3)
    }

    //6.默认参数
    fun test9(x: Int = 0) {
    }

    //7.函数操作符
    //a.自定义操作符 关键字 operator
    operator fun plus(a: Int) {

    }
    //b.基础操作符 ！+ - .. * ／ %
    //c.

    //8.包含函数 in contains
    // x in aa
    // aa.contains(x)

    //9.Invoke 和（） 重载符
    object Test10 {
        operator fun invoke(a: Int) {

        }

        operator fun invoke(a: Int, b: Int) {

        }
    }
    //调用：Test10(1)  Test10(1,2)


    //10.赋值操作符 与java相同
    //+= -= *= ／= %=

    //11.扩展函数
//    fun 类名.扩展方法名(){}
    fun Int.square() {
        this * this
    }
    //子类可重载成员扩展函数

    //12.infix 函数
    //可把两个变量凑成一个二元组Pair
    var train = "aaa" to "bbb"


    //13.函数自面量 （其实就是函数内容）
    var fcn1 = { Log.e("kotlin", "函数赋值给变量") }
    var fcn2 = { msg: Int -> Log.e("kotlin", "函数赋值给变量 带参数的 ${msg}") }


    /**
     *函数标准库
     */
    fun test11() {
        //1.apply 返回调用对象
        Thread(Runnable {
            Log.e("kotlin", "函数赋值给变量")
        }).apply { Log.e("kotlin", "apply 内容执行体,可调用对象的方法${id}") }.start()

        //2.let 函数有返回的话 就是最后一行 或者 指定的retrurn
        "xxx".let {
            Log.e("kotlin", "let 执行")
            Log.e("kotlin", "let 执行${it}")
            //return 99
        }

        //3.with 不用写多次对象名
        var list = ArrayList<String>()
        with(list) {
            add("aaaa")
            add("bbbb")
            add("ccccc")
        }.let { Log.e("kotlin", "with${it}") }

        //apply也可以实现
//        list.apply {
//            add("eeee")
//            add("rrr")
//            add("tttt")
//        }.let {  Log.e("kotlin", "with${it}") }

        //4.run 和apply类似 返回最后行
        list.run {
            add("run1")
            add("run2")
            Log.e("kotlin", "run${this.joinToString()}")
//            return 33
        }
    }


    /**
     *lambda
     */

    // 第一种  //简写 系统识别返回类型
    val sum1 = { x: Int, j: Int -> "String" }
    // 第二种  //完整写法 在前面指定好 接收和返回参数类型
    val sum2: (x: Int, j: Int) -> Unit = { a, b -> a + b }


    fun test12() {
        test13(3, { b: Int, c: Int -> b + 1 + c }) //传入lambda表达式
        Log.e("kotlin", "lambda格式1  ${sum1(1, 3)}")
        Log.e("kotlin", "lambda格式2  ${sum2(1, 2)}")

        sum1(1, 3)
        sum2(1, 2)

    }

    fun test13(x: Int, method: (a: Int, b: Int) -> Unit) { //接收lambda表达式参数 -> Unit表示返回参数
        var i = method(x, 6)
        Log.e("kotlin", "lambda  ${i}")
    }

    /**
     *
     *高阶函数
     */
//    fun 高阶函数名(参数函数名：参数函数类型)：高阶函数返回类型{
//        高阶函数体
//        ...
//    }

    fun test14(){
        val view = View(this)
        view.setOnClickListener{f-> Log.e("kotlin", "lambda高阶函数")}
    }

//    注意：使用Lambda可以省去接口定义和实现这一环节,此接口必须只有一个抽象方法需要实现，才可以使用Lambda替代

//    Lambda表达式也可以传递给一个高阶函数当做参数,因此上述代码中
//    view.setOnClickListener(imageClick),
//    =>
//    view.setOnClickListener({v -> viewClicked(v) })
//
//    在 Kotlin 中有一个约定，如果函数的最后一个参数是一个函数，并且你传递一个 lambda 表达式作为相应的参数，你可以在圆括号之外指定它
//    因此可以实现如下
//    view.setOnClickListener({v -> viewClicked(v) })
//    =>
//    view.setOnClickListener() {v -> viewClicked(v) }
//
//    在 Kotlin中还有另外一个约定，如果一个函数的参数只有一个，并且参数也是一个函数，那么可以省略圆括号
//    view.setOnClickListener() {v -> viewClicked(v) }
//    =>
//    view.setOnClickListener{v -> viewClicked(v) }

//    参考：https://blog.csdn.net/zxm317122667/article/details/78255481

}

